function Foo() {
    getName = function () {
        console.log(1);
    };
    return this;
}
Foo.getName = function () {
    console.log(2);
};
Foo.prototype.getName = function () {
    console.log(3);
};
var getName = function () {
    console.log(4);
};
function getName() {
    console.log(5);
}

// 首先我们看到全局下有两个getName，这里考察的是通过不同方式创建的函数的执行顺序
// 这里虽然代码上声明函数在后，但在执行的时候，会有声明提升，所以会在函数表达式之前执行
// 也就是说，是函数表达式的getName覆盖了函数声明的getName

// 这里的getName是Foo这个函数的属性， 返回2
Foo.getName();
// 这里的getName是Foo函数执行后的返回值this的getName，
// 所以这里需要先判断下this的指向，我们知道，this指向，取决于谁调用了Foo函数，
// 代码中很明显是window调用了Foo函数，所以this指向window
// 然而在Foo函数执行过程中, getName这个函数又被重新赋值了，
// 进而此处打印结果为1
Foo().getName();
// 这里直接调用全局的getName函数，本来返回4
// 但是上一行代码把全局的getName给重新赋值了，所以这边返回1
getName();
// 这里还考验了操作符运算优先等级
// new后边的构造函数时Foo.getName
// 返回2
new Foo.getName();
// (new Foo()).getName(); Foo实例上的getName方法，如果实例对象上没有，就从它构造函数的原型上找，所以返回3
new Foo().getName();

/**
 * 1. 首先new Foo()得到一个Foo实例对象
 * 2. new Foo().getName()是Foo实例对象的getName方法，如果自身没有，就往原型对象上找
 * 3. new (new Foo().getName)()最终返回3
 */
new new Foo().getName();


// 2 1 1 2 3 3